// 在文件中已经声明了两个类Brass和BrassPlus

//   virtual关键字
// 如果方法是通过引用或指针而不是通过对象调用的，他将确定使用哪一种方法. 如果没有关键字virtual,程序将根据引用类型或指针类型选择方法。
// 带有virtual关键字的方法，我们称为虚方法

#include <iostream>
#include "54PolymorphismCharacteristics.hpp"

// 在这里我们看看他们到底有什么不同
// 先创建出两个对象
Brass dom("aquawius",99999, 100);
BrassPlus dot("aquawius",999,99);

int main(int argc, char const *argv[])
{
    // 如果通过对象直接进行调用,那么调用的方法将会根据类型调用对应的方法。
    dom.ViewAcct();
    dot.ViewAcct();

    // 如果这里把派生对象强制转换成基类对象
    Brass cast = (Brass)dot;
    cast.ViewAcct();
    // 直接调用的话也会调用基类的方法


// 如果这里采用的是指针或引用的方式, 注意这里将所有指针或引用的类型声明为基类类型。
    Brass & b1_ref = dom;
    Brass & b2_ref = dot;
// 因为其中的ViewAcct()方法是虚方法,在通过指针或引用进行调用的时候,虚方法将会体现出它的作用
    b1_ref.ViewAcct();      // 调用的是 Brass::ViewAcct()
    b2_ref.ViewAcct();      // 调用的是 BrassPlus::ViewAcct(),因为这个引用引用的是一个BrassPlus对象

    return 0;
}

// 你可能也会看到析构函数是一个虚方法,这样做是为了确保释放派生对象时按正确的顺序调用析构函数。
// 如果指针指向的是BrassPlus对象,将会调用正确的方式调用BrassPlus的析构函数,然后调用Brass的析构函数
// 但是没有使用virtual虚函数的析构函数,将会直接使用Brass的析构函数,然后释放BrassPlus中Brass的部分剩下的内存将无法被释放而产生内存泄露!

// 如果能用同一个数组来保存Brass和BrassPlus对象,将会很有帮助，但是这是不可能的，数组中所有元素的类型必须相同，而Brass和BrassPlus是不同的类型。
// 我们可以创建指向它Brass的指针数组,这样每个元素的类型都相同，但由于使用的是公有继承模型，因此Brass指针既可以指向Brass对象，也可以指向BrassPlus对象
// 因此可以使用一个数组来表示多种类型的对象，这就是多态性
